#include "CurlTool.h"

/************************************************************************
*-0 使用格式化字符串的形式抛出c++标准异常，方便程序使用
************************************************************************/
void Throw(const char* pszFormat, ...)
{
	std::string err;
	va_list args;
	va_start(args, pszFormat);
#if defined(WIN32)
	int nLength = DEFAULT_APP_DATA_SIZE;
#else
	int nLength = vsnprintf(NULL, 0, pszFormat, args);
#endif
	if (nLength < 0)
	{
		err = "Throw : get formatted length failed";
	}
	else
	{
		char* pszBuffer = new char[nLength + 1];
		vsnprintf(pszBuffer, nLength + 1, pszFormat, args);
		err = pszBuffer;
		delete [] pszBuffer;
	}
	va_end(args);

	std::runtime_error error_(err);
	throw error_;
};


//////////////////////////////////////////////////////////////////////////
/// 加载libcurl库
//////////////////////////////////////////////////////////////////////////
bool LibCURL::m_global_init = false;
int LibCURL::Init()
{
    if (m_global_init) return 0;
    try
    {
        CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
        if (res != CURLE_OK)
        {
            Throw("CurlTool全局初始化失败，错误码=%d", (int)res);
        }
    }
    catch (exception& e)
    {
        printf("Error = %s\n", e.what());
        return -1;
    }
    m_global_init = true;
    return 0;
}

//////////////////////////////////////////////////////////////////////////
/// 卸载libcurl库
//////////////////////////////////////////////////////////////////////////
int LibCURL::Fini()
{
    if (m_global_init)
    {
        curl_global_cleanup();
        m_global_init = false;
    }
    return 0;
}




CurlTool::CurlTool(string ftp_ip, string ftp_port, string ftp_user, string ftp_passwd)
    :m_ftp_ip(ftp_ip),m_ftp_port(ftp_port),m_ftp_user(ftp_user),m_ftp_passwd(ftp_passwd)
{

}

CurlTool::~CurlTool()
{
    //dtor
}

size_t CurlTool::WriteFileFunc(void *buffer, size_t size, size_t nmemb, void *stream)
{
    size_t write_size = fwrite(buffer,size,nmemb,(FILE*)stream);
    return write_size;
}

size_t CurlTool::ReadFileFunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
    size_t read_size = fread(ptr,size,nmemb,(FILE*)stream);
    return read_size;
}

/* Never writes anything, just returns the size presented */
size_t CurlTool::DoNothingWrite(char *ptr, size_t size, size_t nmemb, void *userdata)
{
   return size * nmemb;
}



int CurlTool::DownloadFile(string ftp_file, string local_file)
{
    //若目录不存在，则先创建目录
    string sCommand = "[ -d $(dirname  " + local_file +") ] || mkdir -p $(dirname " + local_file + ")";
    system(sCommand.c_str());

    string ftp_url = "ftp://" + m_ftp_ip + ":" + m_ftp_port + "/" + ftp_file;

    FILE* pFile = fopen(local_file.c_str(),"wb");
    if (!pFile)
    {
        Throw("文件%s Open 失败", local_file.c_str());
    }
    CURL *curl = curl_easy_init();
    if(!curl)
    {
        LibCURL::Fini();
        Throw("LibCURL失败");
    }

    curl_easy_setopt(curl, CURLOPT_URL, ftp_url.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlTool::WriteFileFunc);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)pFile);
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_ftp_user.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_ftp_passwd.c_str());
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, m_ftp_error);
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 0L);
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);

    CURLcode res = curl_easy_perform(curl);

    fclose(pFile);
    /* always cleanup */
    curl_easy_cleanup(curl);

    if (res != CURLE_OK)
    {
        Throw("下载文件%s失败 : %s", ftp_file.c_str(), m_ftp_error);
    }

    return 0;
}


int CurlTool::UploadFile(string ftp_file, string local_file)
{
    struct stat file_info;
    curl_off_t fsize;

    /* get the file size of the local file */
    if(stat(local_file.c_str(), &file_info))
    {
        printf("Couldnt open '%s': %s\n", local_file.c_str(), strerror(errno));
        return -1;
    }
    fsize = (curl_off_t)file_info.st_size;

    printf("Local file size: %" CURL_FORMAT_CURL_OFF_T " bytes.\n", fsize);

    /* get a FILE * of the same file */
    FILE *fLocalFile = fopen(local_file.c_str(), "rb");


    CURL *curl = curl_easy_init();
    if(!curl)
    {
        LibCURL::Fini();
        Throw("LibCURL失败");
    }

    string ftp_url = "ftp://" + m_ftp_ip + ":" + m_ftp_port + "/" + ftp_file;

    /* we want to use our own read function */
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadFileFunc);

    /* enable uploading */
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

    /* specify target */
    curl_easy_setopt(curl,CURLOPT_URL, ftp_url.c_str());

    /* now specify which file to upload */
    curl_easy_setopt(curl, CURLOPT_READDATA, fLocalFile);

    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,(curl_off_t)fsize);

    curl_easy_setopt(curl, CURLOPT_USERNAME, m_ftp_user.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_ftp_passwd.c_str());

    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, m_ftp_error);
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
    curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L);
	curl_easy_setopt(curl, CURLOPT_APPEND, 0L);


    CURLcode res = curl_easy_perform(curl);

    fclose(fLocalFile);
    /* always cleanup */
    curl_easy_cleanup(curl);

    if (res != CURLE_OK)
    {
        printf("上传文件%s失败: %s\n", ftp_file.c_str(), strerror(errno));
        //throw("上传文件%s失败 : %s", ftp_file.c_str(), m_ftp_error);
    }

    return 0;
}



//////////////////////////////////////////////////////////////////////////
/// 删除FTP文件
//////////////////////////////////////////////////////////////////////////
int CurlTool::DeleteFile(string ftp_file)
{
	struct curl_slist* slist = NULL;
	string temp_file = "DELE " + ftp_file;
	string ftp_url = "ftp://" + m_ftp_ip + ":" + m_ftp_port;
	slist = curl_slist_append(slist, temp_file.c_str());

	CURL* curl = curl_easy_init();
	curl_easy_setopt(curl, CURLOPT_URL, ftp_url.c_str());
    curl_easy_setopt(curl, CURLOPT_USERNAME, m_ftp_user.c_str());
    curl_easy_setopt(curl, CURLOPT_PASSWORD, m_ftp_passwd.c_str());
	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, m_ftp_error);
	curl_easy_setopt(curl, CURLOPT_QUOTE, slist);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &DoNothingWrite);
	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
	CURLcode res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	curl_slist_free_all(slist);

	if (res != CURLE_OK)
	{
		Throw("删除FTP文件%s失败 : %s", ftp_file.c_str(), m_ftp_error);
	}
	return 0;
}

